#include <iostream>
#include "TrainingData.h"
#include "Tree.h"
#include "randomForest.h"
#include <map>
#include <algorithm>
#include <memory>
#include <stdlib.h>
#include <crtdbg.h>
#include <cassert>
#include <fstream>
#include <time.h>
#include "timer.h"


#define CRTDBG_MAP_ALLOC
#define DEBUG_MEMORY_LEAK

using namespace std;


int main() {

	unsigned int errors = 0;
	
	#ifdef DEBUG_MEMORY_LEAK
		_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
		_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
		_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
		_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
		_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
		_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
	#endif
	
	timer t;

	{

		fstream benchmarks("benchmarks.txt", fstream::out);
		
		srand ( time(NULL) );

		cout << "Reading training data..." << endl;
		
		TrainingData<float> testingData;
		testingData.readTrainingData("optdigits.testing.data");
		

		unsigned int i = 0;
		for(unsigned int depthTree =10; depthTree <= 10; depthTree+=5) {
			benchmarks << endl;
			for(unsigned int numTree = 3000; numTree <= 3000; numTree+=10) {
				for(unsigned char algorithm=0; algorithm <=0; algorithm ++) {
					
					i++;
					
					if(numTree ==0)
						continue;

					errors = 0;

					/*if(algorithm ==0)
						cout << "ALG: RANDOM, ";
					else if(algorithm == 1)
						cout << "ALG: GINI, ";
					else if(algorithm == 2)
						cout << "ALG: RANDOMIDEZ GINI, ";*/
					

					//cout << "NumTrees: " << numTree << ", depth: " << depthTree << endl;
					
					t.start();
					/* Create the forest */
					RandomForest<float> randomForest;
					
					bool enable_bagging = false;
					randomForest.createForest("optdigits.data",numTree,depthTree, algorithm, enable_bagging, 1000);

					t.stop();

					cout << "Training time is: " << t.elapsed_ms()/1000 << endl;

					//cout << "Classifying..." << endl;
					t.start();
					for(unsigned int j=0; j < testingData.size(); j++) {
						unsigned int c = randomForest.classify(testingData.getRecord(j));

						/*cout	<< "Class predicted " 
								<< c
								<< ", reale: " 
								<< trainingData.getRecord(j).getClass()<< endl;*/

						if(c != testingData.getRecord(j).getClass()) {
							errors++;
						}
					}
					t.stop();

					cout << "Classification time is: " << t.elapsed_ms()/1000 << endl;

					/*if(algorithm ==0)
						cout << "ALG: RANDOM, ";
					else if(algorithm == 1)
						cout << "ALG: GINI, ";
					else if(algorithm == 2)
						cout << "ALG: RANDOMIDEZ GINI, ";
					*/

					benchmarks << (float)(errors/(float)testingData.size())*100 << " ";
					//cout << "Testing data: " << testingData.size() << endl;
					//cout << "NumTrees: " << numTree << ", depth: " << depthTree << ", ";
					cout << (float)(errors/(float)testingData.size())*100 << " %, " << errors << " errors." ;
					//cout << " Time: " << t.elapsed_ms()/(1000) << endl;
				}
			}
		}
		benchmarks.close();
	}

	#ifdef DEBUG_MEMORY_LEAK
		_CrtDumpMemoryLeaks();
	#endif

}
